﻿using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using AdTech.Common;

namespace AdTech.Snap
{
    /// <summary>
    /// Represents an object containing serializable properties used for a QRCode encoding request.
    /// </summary>
    [DataContract(Name = "qrcode", Namespace = "")]
    public class QRCode
    {
        // Fields
        private QRCodeFormat _Format;
        private short? _Version;

        // Properties
        /// <summary>
        /// Gets or sets a message to be encoded in QR code.
        /// </summary>
        [DataMember(Name = "content", IsRequired = false, EmitDefaultValue = false)]
        public string Content { get; set; }

        /// <summary>
        /// Gets or sets the output format.
        /// </summary>
        public QRCodeFormat Format
        {
            get { return this._Format; }
            set { this.FormatString = value.ToString().ToLower(); this._Format = value; }
        }
        [DataMember(Name = "format", IsRequired = false, EmitDefaultValue = false)]
        private string FormatString { get; set; }

        /// <summary>
        /// Gets or sets a QR code module size in pixels.
        /// </summary>
        [DataMember(Name = "size", IsRequired = false, EmitDefaultValue = false)]
        public int? Size { get; set; }

        /// <summary>
        /// Gets or sets a QR code version. Values 1-40 or null to be automatically determined.
        /// </summary>
        [DataMember(Name = "version", IsRequired = false, EmitDefaultValue = false)]
        public short? Version
        {
            get { return this._Version; }
            set
            {
                if (this._Version != value)
                {
                    if (value == null || (value >= 1 && value <= 40))
                        this._Version = value;
                    else
                        throw new ArgumentException("Version must be 1-40 or null to be automatically determined!");
                }
            }
        }

        /// <summary>
        /// Gets or sets the padding value in modules.
        /// </summary>
        [DataMember(Name = "padding", IsRequired = false, EmitDefaultValue = false)]
        public int? Padding { get; set; }

        /// <summary>
        /// Gets or sets the encoding mode.
        /// </summary>
        [DataMember(Name = "em", IsRequired = false, EmitDefaultValue = false)]
        public string EncodeMode { get; set; }

        /// <summary>
        /// Gets or sets the error correction level. Message can be recovered if QR code is partially damaged,
        /// recovery percent defines the error correction level (up to 30%).
        /// </summary>
        [DataMember(Name = "ec", IsRequired = false, EmitDefaultValue = false)]
        public string ErrorCorrection { get; set; }

        /// <summary>
        /// Gets or sets a XAML compatible hex color for foreground.
        /// </summary>
        [DataMember(Name = "foreground", IsRequired = false, EmitDefaultValue = false)]
        public string ForegroundColor { get; set; }

        /// <summary>
        /// Gets or sets a XAML compatible hex color for background.
        /// </summary>
        [DataMember(Name = "background", IsRequired = false, EmitDefaultValue = false)]
        public string BackgroundColor { get; set; }

        /// <summary>
        /// Gets or sets an error message. Error is thrown when reponse HTTP header contains "X-Api-Error".
        /// </summary>
        [DataMember(Name = "error", IsRequired = false, EmitDefaultValue = false)]
        public string Error { get; set; }

        // Constructor
        /// <summary>
        /// Initializes a new instance of the <see cref="AdTech.Snap.QRCode"/> class.
        /// </summary>
        public QRCode()
        {
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="AdTech.Snap.QRCode"/> class.
        /// </summary>
        /// <param name="content">The content to be encoded.</param>
        public QRCode(string content)
        {
            this.Content = content;
        }

        /// <summary>
        /// Serializes the current object to JSON
        /// </summary>
        /// <returns>A JSON serialized string of the current object</returns>
        public string Serialize()
        {
            using (MemoryStream stream = new MemoryStream())
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(this.GetType());
                serializer.WriteObject(stream, this);
                stream.Position = 0;
                using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                {
                    return reader.ReadToEnd();
                }
            }
        }

        /// <summary>
        /// Deserializes the given JSON string to an <see cref="AdTech.Snap.QRCode"/> object.
        /// </summary>
        /// <param name="raw">The serialized JSON string.</param>
        /// <returns>The deserialized <see cref="AdTech.Snap.QRCode"/> object.</returns>
        public static QRCode Deserialize(string raw)
        {
            using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(raw)))
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(QRCode));
                return (QRCode)serializer.ReadObject(stream);
            }
        }
    }
}
